package com.apes.fn.fico.reimbursement.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.fico.reimbursement.model.*;
import com.apes.fn.fico.reimbursement.repository.ExpenseDebitItemRepository;
import com.apes.fn.fico.reimbursement.repository.ExpenseDebitRepository;
import com.apes.fn.fico.reimbursement.repository.ReimbursementRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.*;
import com.apes.hr.base.model.Employee;
import com.apes.hr.base.repository.EmployeeRepository;
import com.apes.hr.base.repository.WorkPostRepository;
import com.apes.importData.model.ImportControls;
import com.apes.importData.respository.ImportControlsRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.PostRepository;
import com.apes.scm.rbac.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 费用报销
 * Created by lishikun on 2021/1/27 11:26
 */
@Service("reimbursementService")
public class ReimbursementService extends DomainService {
    @Autowired
    ReimbursementRepository reimbursementRepository;

    @Autowired
    ExpenseDebitRepository expenseDebitRepository;

    @Autowired
    PostRepository postRepository;

    @Autowired
    ImportControlsRepository importControlsRepository;

    /**
     * 创建
     *
     * @param request
     * @return
     */
    public Reimbursement create(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        //按需求所说 岗位为空时取操作员的人员档案中的岗位
        Optional.ofNullable(request.getPerson()).ifPresent(person -> {
            Employee employee = SpringManager.getBean(EmployeeRepository.class).findByParty(((PartyRole) person).getParty());
            if (!Tools.isNull(employee)) {
                reimbursement.setWorkPost(employee.getPost());
            }
        });
        //校验
        checkReimbursement(reimbursement);
        reimbursement.compute();
        //冻结借支单还款金额
        freezeMethod(reimbursement, 1);
        return reimbursementRepository.saveAndFlush(reimbursement);
    }

    /**
     * 更新
     *
     * @param request
     * @return
     */
    public Reimbursement update(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        //校验
        checkReimbursement(reimbursement);
        reimbursement.compute();
        Reimbursement repositoryOne = reimbursementRepository.findOne(reimbursement.getId());
        //解冻借支单还款金额
        freezeMethod(repositoryOne, -1);
        //冻结借支单还款金额
        freezeMethod(reimbursement, 1);
        return reimbursementRepository.saveAndFlush(reimbursement);
    }

    /**
     * 删除
     *
     * @param request
     * @return
     */
    public String delete(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        //解冻借支单还款金额
        freezeMethod(reimbursement, -1);
        reimbursementRepository.delete(reimbursement);
        return "删除成功";
    }

    // 费用报销单各类费用主管OA保存
    public Reimbursement saveOA(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        return reimbursementRepository.saveAndFlush(reimbursement);
    }

    /**
     * 费用会计编辑
     *
     * @param request
     * @return
     */
    public Reimbursement edit(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        reimbursement.setCause(reimbursementRepository.findOne(reimbursement.getId()).getCause());
        reimbursement.compute();
        return reimbursementRepository.saveAndFlush(reimbursement);
    }

    /**
     * 完成
     *
     * @param request
     * @return
     */
    public Reimbursement finish(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        reimbursement.setState("cashier");
        if (reimbursement.getReimbursementItems().stream().mapToDouble(ReimbursementItem::getAwaitPayAmount).sum() == 0) {
            reimbursement.setState("finish");
            repayment(reimbursement);
        }
        return reimbursementRepository.saveAndFlush(reimbursement);
    }

    /**
     * 付款
     *
     * @param request
     */
    public Reimbursement pay(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        // 检测付款回执文件、银行流水号、付款账户填写情况
        if (Objects.isNull(reimbursement.getFileAddress()))
            throw new RuntimeException("付款回执文件没有上传");

//        //处理交易流水
//        reimbursement.getTransactionFlowItems().forEach(transactionFlowItem -> {
//            double amount = Arith.add(transactionFlowItem.getPayAmount(), transactionFlowItem.getPaymentAmount());
//            if (amount > transactionFlowItem.getAmount()) {
//                throw new RuntimeException("付款金额不能大于交易额");
//            }
//            transactionFlowItem.setPayAmount(amount);
//        });
        //减少原单的使用额
        useAmountMethod(reimbursementRepository.findOne(reimbursement.getId()), -1);
        //增加使用额
        useAmountMethod(reimbursement, 1);


        //处理借支单
        if (reimbursement.getReimbursementType().getId().equals("BorrowMoney") && Objects.isNull(reimbursement.getPayId())) {
            //借支还款首次付款回写借支单
            repayment(reimbursement);
        }
        //处理付款状态
        reimbursement.computeAmt();
        reimbursement.setPayId(this.getPerson(request));
        reimbursement.setPayDate(new Date());
        return reimbursementRepository.saveAndFlush(reimbursement);
    }


    /**
     * 冻结/解冻借支单还款金额
     *
     * @param reimbursement
     * @param flag
     */
    private void freezeMethod(Reimbursement reimbursement, int flag) {
        if (reimbursement.getReimbursementType().getId().equals("BorrowMoney")) {
            //借支单还款金额冻结
            reimbursement.getReimbursementItems().forEach(reimbursementItem -> {
                reimbursementItem.getReimbursementDebits().forEach(reimbursementDebit -> {
                    ExpenseDebitItem expenseDebitItem = reimbursementDebit.getExpenseDebitItem();
                    expenseDebitItem.setFreezeAmount(Arith.round(expenseDebitItem.getFreezeAmount() + reimbursementDebit.getWrittenAmount() * flag, 2));
                    ExpenseDebit expenseDebit = expenseDebitItem.getExpenseDebit();
                    expenseDebit.computeAmt();
                    expenseDebitRepository.saveAndFlush(expenseDebit);
                });
            });
        }
    }


    /**
     * 银行流水使用额
     *
     * @param reimbursement
     */
    private void useAmountMethod(Reimbursement reimbursement, int flag) {
        //增加银行流水使用额
//        reimbursement.getTransactionFlowItems().forEach(transactionFlowItem -> {
//            TransactionFlow transactionFlow = transactionFlowItem.getTransactionFlow();
//            transactionFlow.computeAmt(transactionFlowItem.getPaymentAmount() * flag);
//            SpringManager.getBean(TransactionFlowRepository.class).saveAndFlush(transactionFlow);
//        });
    }

    /**
     * 借支单还款
     *
     * @param reimbursement
     */
    private void repayment(Reimbursement reimbursement) {
        if (reimbursement.getReimbursementType().getId().equals("BorrowMoney")) {
            //借支单还款
            reimbursement.getReimbursementItems().forEach(reimbursementItem -> reimbursementItem.getReimbursementDebits().forEach(reimbursementDebit -> {
                ExpenseDebitItem expenseDebitItem = reimbursementDebit.getExpenseDebitItem();
                expenseDebitItem.setFreezeAmount(Arith.sub(expenseDebitItem.getFreezeAmount(), reimbursementDebit.getWrittenAmount()));
                expenseDebitItem.setRepaymentAmount(Arith.add(expenseDebitItem.getRepaymentAmount(), reimbursementDebit.getWrittenAmount()));
                ExpenseDebit expenseDebit = expenseDebitItem.getExpenseDebit();
                expenseDebit.computeAmt();
                expenseDebit.computeState();
                // 回写借支单还款信息
                ExpenseRepaymentItem expenseRepaymentItem = new ExpenseRepaymentItem();
                expenseRepaymentItem.setId(SpringManager.getBean(SequenceService.class).getId(ExpenseRepaymentItem.CONST_TABLE_NAME));
                // 设置还款金额为剩余金额
                expenseRepaymentItem.setRepaymentMoney(reimbursementDebit.getWrittenAmount());
                expenseRepaymentItem.setSource(reimbursement.getId());
                expenseRepaymentItem.setSourceBusinessType(reimbursement.getInnerBusinessType());
                expenseRepaymentItem.setExpenseDebit(expenseDebit);
                expenseRepaymentItem.setState("done");
                expenseDebit.getExpenseRepaymentItems().add(expenseRepaymentItem);
                expenseDebitRepository.saveAndFlush(expenseDebit);

            }));
        }
    }


    // 审核
    public Reimbursement approve(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        reimbursement.setState("approve");
        // 设置审核人和时间
        reimbursement.setApproveId(this.getPerson(request));
        reimbursement.setApproveDate(new Date());
        // 设置发起人
        String creatorId = reimbursement.getCreator();
        reimbursement.setOASponsor(SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", creatorId)).get(0).getId().toString());
        checkReimbursement(reimbursement);
        // 设置超过30天未冲帐的备注

        reimbursement.setRemark(reimbursement.getReimbursementItems().stream().filter(
                        distinctByKey(reimbursementItem -> reimbursementItem.getDutyCenter().getId())
                ).map(reimbursementItem -> Optional.ofNullable((String) invoke("fn.expenseDebit.findAllByCostCenter",
                        MapUtil.mapper("data", MapUtil.mapper("id", reimbursementItem.getDutyCenter().getId())))).orElse(null))
                .filter(Objects::nonNull).collect(Collectors.joining(";")));
        setSupperOA(reimbursement);
        Reimbursement flush = reimbursementRepository.saveAndFlush(reimbursement);
        inspectionFeeType(flush, flush.getFeeType().getCode());
        return flush;
    }

    // 拒绝
    public Reimbursement refuse(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        freezeMethod(reimbursement, -1);
        reimbursement.setState("repeal");
        return reimbursementRepository.saveAndFlush(reimbursement);
    }

    // 退回
    public Reimbursement goBack(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        if (reimbursement.getRemark() == null && "".equals(reimbursement.getRemark()))
            throw new RuntimeException("请在备注上写明退回原因");
        reimbursement.setState("create");
        return reimbursementRepository.saveAndFlush(reimbursement);
    }

    // 出纳
    public Reimbursement cashier(SimpleRequest request) {
        Reimbursement reimbursement = reimbursementRepository.findOne(request.get("id").toString());
        reimbursement.setState("cashier");
        return reimbursementRepository.saveAndFlush(reimbursement);
    }


    // OA流程上传付款信息
    public Reimbursement upPaymentInfo(SimpleRequest request) {
        Reimbursement reimbursement = request.getO(Reimbursement.class);
        // 检测付款回执文件、银行流水号、付款账户填写情况
        if (Objects.isNull(reimbursement.getFileAddress()))
            throw new RuntimeException("付款回执文件没有上传");
//        if (Objects.isNull(reimbursement.getBankSerialNumber()))
//            throw new RuntimeException("银行流水号没有选择！");
//        if (Objects.isNull(reimbursement.getBankSerialNumber()))
//            throw new RuntimeException("付款账户没有选择！");

        return reimbursementRepository.saveAndFlush(reimbursement);
    }

//    // 费用报销单格式化数据
//    public Reimbursement formatReimbursementDataAndDetect(Reimbursement reimbursement) {
//        if (Objects.nonNull(reimbursement.getReimbursementItems())) {
//            reimbursement.getReimbursementItems().forEach(reimbursementItem ->{
//                if (reimbursementItem.getExpenseDebitSet() != null) {
//                    List<String> expenseDebitIds = reimbursementItem.getExpenseDebitSet().stream().map(ExpenseDebit::getId).collect(Collectors.toList());
//                    reimbursementItem.getExpenseDebitSet().clear();
//                    expenseDebitIds.forEach(id -> {
//                        reimbursementItem.getExpenseDebitSet().add(expenseDebitRepository.findOne(id));
//                    });
//                }
//
//            });
//        }
//        return reimbursement;
//    }

//    // 流程回写费用借支单信息
//    private Reimbursement infoExpenseDebit(Reimbursement reimbursement){
//
//        reimbursement.getReimbursementItems().forEach(reimbursementItem -> {
//            // 报销总金额
//            final double[] reimbursementTotal = {reimbursementItem.getReimbursementTotal()};
//
//            // 根据借支单审核完成时间升序
//            List<ExpenseDebit> collect = reimbursementItem.getExpenseDebitSet().stream()
//                    .sorted(Comparator.comparing(ExpenseDebit::getRepaymentDate))
//                    .collect(Collectors.toList());
//
//            for (ExpenseDebit expenseDebit : collect) {
//                //  报销总金额 - 借支金额 > 0 设置借支单完成状态
//                if ( reimbursementTotal[0] - (expenseDebit.getPendingSum() )>= 0 ) {
//                    // 借支单完成状态
//                    expenseDebit.setState("finish");
//                    // 回写借支单还款信息
//                    // 设置费用还款单的还款金额，来源单据，来源类型
//                    ExpenseRepaymentItem expenseRepaymentItem = new ExpenseRepaymentItem();
//                    expenseRepaymentItem.setId(SpringManager.getBean(SequenceService.class).getId(expenseRepaymentItem.CONST_TABLE_NAME));
//                    // 设置还款金额为剩余金额
//                    expenseRepaymentItem.setRepaymentMoney(expenseDebit.getPendingSum());
//                    expenseRepaymentItem.setSource(reimbursement.getId());
//                    expenseRepaymentItem.setSourceBusinessType(reimbursement.getInnerBusinessType());
//                    expenseRepaymentItem.setExpenseDebit(expenseDebit);
//                    expenseDebit.getExpenseRepaymentItems().add(expenseRepaymentItem);
//                    reimbursementTotal[0] = reimbursementTotal[0] - expenseDebit.getPendingSum();
//
//                }
//                // 报销总金额 - 借支金额 < 0 结束整个回填还款过程
//                else {
//                    // 设置费用还款单的还款金额，来源单据，来源类型
//                    ExpenseRepaymentItem expenseRepaymentItem = new ExpenseRepaymentItem();
//                    expenseRepaymentItem.setId(SpringManager.getBean(SequenceService.class).getId(expenseRepaymentItem.CONST_TABLE_NAME));
//                    // 还款金额为报销金额
//                    expenseRepaymentItem.setRepaymentMoney(reimbursementTotal[0]);
//                    expenseRepaymentItem.setSource(reimbursement.getId());
//                    expenseRepaymentItem.setSourceBusinessType(reimbursement.getInnerBusinessType());
//                    expenseRepaymentItem.setExpenseDebit(expenseDebit);
//                    expenseDebit.getExpenseRepaymentItems().add(expenseRepaymentItem);
//                    break;
//                }
//            }
//            collect.forEach(expenseDebit -> invoke("fn.expenseDebit.repayment", MapUtil.mapped(expenseDebit)));
//        });
//        return reimbursement;
//    }


    // 校验报销的金额是否需要走OA流程
    public Reimbursement checkReimbursement(Reimbursement reimbursement) {
        reimbursement.setNeedOA(true);
        for (ReimbursementItem reimbursementItem : reimbursement.getReimbursementItems()) {
            if (Objects.nonNull(reimbursementItem.getInvoice()) && reimbursementItem.getInvoice().getDescription().equals("专票")) {
                if (Tools.isNull(reimbursementItem.getInvoiceNumber()) || Tools.isNull(reimbursementItem.getTax()) || Tools.isNull(reimbursementItem.getPriceTax()))
                    throw new RuntimeException("专票：发票号码、价税合计金额、税率,为必填");
            }


        }
        if (reimbursement.getReimbursementType().getId().equals("BorrowMoney") && reimbursement.getReimbursementItems().stream().anyMatch(reimbursementItem -> reimbursementItem.getReimbursementDebits().isEmpty())) {
            throw new RuntimeException(reimbursement.getReimbursementType().getDescription() + "时借支明细不允许为空！");
        }
        return reimbursement;
    }

    private void setSupperOA(Reimbursement reimbursement) {
        // 控制父类审批
        String id = SpringManager.getBean(WorkPostRepository.class).findOne(reimbursement.getWorkPost().getId()).getParents().getId();
        String workPostId = reimbursement.getWorkPost().getId();
        if ("0000016".equals(workPostId)) {
            reimbursement.setNeedSupperOA("1");
            return;
        }
        if ("0000187".equals(id) && "DecorationCost".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");     // 上级岗位
        else if ("0000095".equals(id) && "FinanceCost".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000105".equals(id) && "BusinessExpenses".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000080".equals(id) && "UnionType".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000172".equals(id) && "CustomerFee".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000115".equals(id) && "InfoCost".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000044".equals(id) && "PurchasingCost1".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000043".equals(id) && "Logistics".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000027".equals(id) && "DoorPipe".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000109".equals(id) && "DataType".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000140".equals(id) && "OperationsCenter".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000191".equals(id) && "Burst".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0001272".equals(id) && "BrandType".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else if ("0000822".equals(id) && "Training".equals(reimbursement.getFeeType().getCode()))
            reimbursement.setNeedSupperOA("1");
        else reimbursement.setNeedSupperOA("0");
    }

    /**
     * 检验费用类型
     *
     * @param reimbursement
     * @param feeTypeCode
     */
    private void inspectionFeeType(Reimbursement reimbursement, String feeTypeCode) {
        switch (feeTypeCode) {
            //信息类费用
            case "InfoCost":
                assignmentCandidates(reimbursement, "0000115");
                break;

            //商务类费用
            case "BusinessExpenses":
                assignmentCandidates(reimbursement, "0000105");
                break;

            //客服类费用
            case "CustomerFee":
                assignmentCandidates(reimbursement, "0000172");
                break;

            //采购类费用(外协不得垫付后报销)
            case "PurchasingCost1":
                assignmentCandidates(reimbursement, "0000044");
                break;

            //采购类（设备维修）费用
            case "PurchasingCost2":
                reimbursement.setCandidates(JSON.toJSONString(Arrays.asList("305", "958")));
                break;

            //装修类费用
            case "DecorationCost":
                assignmentCandidates(reimbursement, "0000187");
                break;

            //财务类费用
            case "FinanceCost":
                assignmentCandidates(reimbursement, "0000095");
                break;

            //行政类费用
            case "Administrative":
                //工会类费用
            case "UnionType":
                assignmentCandidates(reimbursement, "0001072");
                break;

            //物流类费用
            case "Logistics":
                assignmentCandidates(reimbursement, "0000043");
                break;

            //门管技术类费用
            case "DoorPipe":
                assignmentCandidates(reimbursement, "0000027");
                break;

            //数据类费用
            case "DataType":
                assignmentCandidates(reimbursement, "0000109");
                break;

            //市场中心类
            case "Market":

                //运营中心费用
            case "OperationsCenter":
                assignmentCandidates(reimbursement, "0000140");
                break;

            //连发类费用
            case "Burst":
                assignmentCandidates(reimbursement, "0000079");
                break;

            //培训类费用
            case "Training":
                assignmentCandidates(reimbursement, "0000822");
                break;

            //人资类费用
            case "HumanResources":
                assignmentCandidates(reimbursement, "0001232");
                break;

            //证券法务类费用
            case "SecuritiesLegalAffairs":
                assignmentCandidates(reimbursement, "0001229");
                break;

            //SAAS研发类费用
            case "S006500":
                assignmentCandidates(reimbursement, "0000140");
                break;
            //品牌部费用
            case "BrandType":
                assignmentCandidates(reimbursement, "0001272");
                break;

            default:
                throw new RuntimeException("当前费用类型未定义待办岗位！无法发起OA");
        }
    }

    /**
     * 设置各类费用审批主管
     *
     * @param reimbursement
     * @param postId
     */
    private void assignmentCandidates(Reimbursement reimbursement, String postId) {
        List<Post> posts = postRepository.findAllByWorkPostId(postId);
        List<User> agents = new ArrayList<>();
        if (!posts.isEmpty()) {
            posts.forEach(post -> {
                List<User> users = SpringManager.getBean(UserRepository.class).findByPost(post.getId());
                if (!users.isEmpty()) agents.addAll(users);
            });
        }
        if (!agents.isEmpty()) {
            List<String> users = new ArrayList<>();
            agents.stream().distinct().forEach(agent -> {
                users.add(String.valueOf(agent.getId()));
            });
            reimbursement.setCandidates(JSONObject.toJSONString(users));
        }
    }


    /**
     * 根据成本中心查询借支信息
     *
     * @param request
     * @return
     */
    public List<ReimbursementDebit> findAllByDutyCenter(SimpleRequest request) {
        String dutyCenter = request.get("dutyCenter");
        List<ExpenseDebitItem> expenseDebitItems = SpringManager.getBean(ExpenseDebitItemRepository.class).findAllByDutyCenter(dutyCenter);
        List<ReimbursementDebit> reimbursementDebits = new ArrayList<>();
        expenseDebitItems.forEach(expenseDebitItem -> {
            ReimbursementDebit reimbursementDebit = new ReimbursementDebit();
            reimbursementDebit.setExpenseDebitItem(expenseDebitItem);
            double amount = expenseDebitItem.getExpenseAmount() - expenseDebitItem.getRepaymentAmount() - expenseDebitItem.getFreezeAmount() - expenseDebitItem.getCancelAmount();
            reimbursementDebit.setWrittenAmount(amount);
            reimbursementDebit.setPendAmount(amount);
            reimbursementDebit.setRepaymentAmount(expenseDebitItem.getRepaymentAmount() + expenseDebitItem.getFreezeAmount());
            reimbursementDebits.add(reimbursementDebit);
        });
        return reimbursementDebits;
    }

    /**
     * 根据报销人查
     *
     * @param request
     * @return
     */
    public Map findByEmployee(SimpleRequest request) {
        String employeeId = request.get("employeeId");
        Page<Map> page = reimbursementRepository.findByEmployee(employeeId, PageRequest.of(request.get("page"), request.get("size")));
        Map mapper = MapUtil.mapped(page);
        if (page.getContent().size() == 0) {
            mapper.put("msg", "未找到历史数据！");
        }
        return mapper;

    }

    /**
     * 根据map里的某个key值去重
     *
     * @param keyExtractor
     * @param <T>
     * @return
     */
    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    public JSONObject beImportReimbursement(SimpleRequest request) {
        JSONObject importData = request.get("importData");//Excel信息
        List<Map> data = request.get("data");                     //获取页面标签信息
        JSONObject exclObject = new JSONObject();                  //返回值

        //以headerName为key 存储cellEditor,cellEditorParams,downFormatter,field
        Map<String, Map> header = data.stream().collect(Collectors.toMap(x -> x.get("name").toString(), x -> x));

        //传来的Key 未知，遍历
        importData.forEach((k, v) -> {
            //获得value===Excel内容
            JSONArray excl = (JSONArray) importData.get(k); //excl原值
            JSONArray result = new JSONArray();         //返回值

            //map存放匹配过的数据------
            Map<Object, Object> resultMap = new HashMap();

            JSONArray firstLine = (JSONArray) excl.get(0);      //firstLine==Excel表头
            result.add(firstLine);
            //遍历value===遍历excel每一行
            for (int i = 0; i < excl.size(); i++) {
                if (i == 0) {  //跳过表头
                    continue;
                }
                JSONArray currentLine = (JSONArray) excl.get(i); //获取当前行
                if (currentLine.size() == 0) {
                    continue; //跳过空白行
                }
                for (int j = 0; j < currentLine.size(); j++) {     //遍历每一行内容

                    Object line = currentLine.get(j);//行内容

                    //如果当前单元格内容已经存在于map中，直接拿取
                    if (resultMap.containsKey(firstLine.get(j) + ":" + line)) {  //KEY:Excel列名+单元格内容
                        currentLine.set(j, resultMap.get(firstLine.get(j) + ":" + line));
                        continue;
                    }

                    //获取表头标题对应的field值
                    if (!header.containsKey(firstLine.getString(j))) {
                        throw new RuntimeException(String.format("Excl表头中[%s]在界面中无对照！请检查！", firstLine.getString(j)));
                    }
                    String field = (String) header.get(firstLine.getString(j)).get("field");
                    if (field.equals("operation")) {
                        currentLine.set(j, "");
                        continue; //跳过序号
                    }

                    //获取实体的领域类
                    String domainTypeName = JpaUtil.getAllDomainType().stream()
                            .filter(s -> ReflectUtil.getClass(s).getSimpleName().equalsIgnoreCase(field))
                            .findFirst().orElse(null);

                    if (domainTypeName == null) {                       //获取不到实体的领域类
                        //查询对照表
                        ImportControls importControls = importControlsRepository.findAllByBizField(field);
                        if (importControls != null)
                            domainTypeName = JpaUtil.getDomainClass(importControls.getBusinessType().getId()).getName();
                    }
                    if (domainTypeName != null) {                       //基本数据类型,不做改变；或者未录入对照表
                        CustomRepository repository = JpaUtil.getRepository(domainTypeName);

                        Object value = null;

                        try {
                            Serializable id = JpaUtil.getId(domainTypeName, line.toString());
                            value = repository.findOne(id);
                        } catch (Exception e) {
                        }

                        //检查是否枚举属性
                        if (domainTypeName.equals("com.apes.scm.masterdata.enumeration.model.Enumeration")) {
                            value = repository.findOne(JpaDsl.toCriteriaByEq("description", line, "type.id", field)).orElse(null);
                        }

                        //检查是否当事人角色属性
                        if (value == null && domainTypeName.equals("com.apes.scm.masterdata.party.model.PartyRole")) {
                            try {
                                char[] chars = field.toCharArray();
                                chars[0] = chars[0] ^= 32;
                                value = repository.findOne(JpaDsl.toCriteriaByEq("party.name", line, "role.id", String.valueOf(chars))).orElse(null);
                            } catch (Exception e) {
                                throw new RuntimeException(firstLine.getString(j) + ":" + line + " 在对应表中存在重名或无法根据当前条件获取，导入终止，建议检查此列数据，修改为ID导入。");
                            }

                        }

                        if (value == null) {
                            try {
                                value = repository.findOne(JpaDsl.toCriteriaByEq("name", line)).orElse(null);

                            } catch (Exception e) {
                                throw new RuntimeException(firstLine.getString(j) + ":" + line + " 在对应表中存在重名或无法根据当前条件获取，导入终止，建议检查此列数据，修改为ID导入。");
                            }
                        }

                        if (value == null) {
                            throw new RuntimeException(firstLine.getString(j) + ":" + line + " 命名不规范或者在对照表中不存在，导入终止，建议检查此列记录。");
                        }
                        if ("partyRole".equals(field)) {
                            PartyRole partyRole = (PartyRole) value;
                            if (!"Employee".equals(partyRole.getRole().getId()))
                                throw new RuntimeException("报销人：" + partyRole.getId() + " " + partyRole.getName() + " 非公司员工,请检查");
                        }

                        //有且只有此一行记录,修改Excel内容
                        currentLine.set(j, value);
                        //存入map
                        resultMap.put(firstLine.get(j) + ":" + line, value); //KEY:Excel列名+单元格内容
                    } else { //基本数据类型
                        if (currentLine.get(j) == null) {  // 为空时传回''
                            (currentLine).set(j, "");
                        }
                    }
                }
                result.add(currentLine);
                exclObject.put(k, result);
            }
        });

        return exclObject;
    }
}
